package plgnet

import (
	"dgo/MyProj/PrjConf"
	"dgo/MyProj/PrjHttpUtils"
	"dgo/goutils/gohttp"
	"dgo/goutils/utils"
	"dgo/plg/plgbase"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

type httpViewRec struct {
	fromaddr      string
	recvt         time.Time
	requestHeader utils.BytesBuilder
	requestBody   utils.BytesBuilder
}

/*
*

	插件Http控制插件
	默认Http服务
	该插件推荐只创建一个
*/
type PlgNetHttpView struct {
	plgbase.PlgBase
	lastMap utils.GSyncMapGroup
	uri     string
}

func CreatePlgNetHttpViewFunc(args ...interface{}) (rval interface{}, err error) {
	return &PlgNetHttpView{}, nil
}

func (this *PlgNetHttpView) OnCreate() {

}

func (this *PlgNetHttpView) Close() error {

	return nil
}

/*
**

	{
	  "id": "plghttpctrl",
	  "type": "net.http.plgctrl",
	  "conf": {
	    "uri":"/api/view"
	  }
	}
*/
func (this *PlgNetHttpView) ReloadConf(conf *wrapper.SuperValue) error {
	conf.CheckExistsStrFunc("uri", func(strv string) {
		strv = ReplacePlaceholderForFileName(strv)
		strv = utils.ReplacePlaceholder(strv, "$$", "$$")
		if this.uri != strv {
			if len(this.uri) > 0 {
				gohttp.UnHandle(this.uri)
			}
			this.uri = strv
			gohttp.HandleFunc(this.uri, func(w http.ResponseWriter, r *http.Request) {
				id := r.URL.Query().Get("id")
				if len(id) == 0 {
					id = "DEFAULT"
				}
				rec := &httpViewRec{}
				rec.fromaddr = r.RemoteAddr
				rec.recvt = time.Now()
				PrjHttpUtils.GetRequestHeader(r.Header, ":", "\r\n", &rec.requestHeader)
				body, _ := ioutil.ReadAll(r.Body)
				rec.requestBody.Write(body)
				this.lastMap.Set(id, rec)
			})
		}
	})

	return nil
}

func (this *PlgNetHttpView) OnHttpStatus(rec *PlgHttpRec) (rval interface{}, errcode int, err error) {
	id := rec.QryAsString("id", "")
	if len(id) == 0 {
		id = "DEFAULT"
	}

	obj := this.lastMap.Get(id, nil)
	if obj == nil {
		rec.RespW.Write([]byte(fmt.Sprintf("%s not found!", id)))
		return
	}

	last := obj.(*httpViewRec)
	var rb utils.BytesBuilder
	rb.Appendf("from:%s, time:%s\r\n================================\r\n", last.fromaddr, utils.DateTimeString2(last.recvt))
	rb.AppendStr(last.requestHeader.String())
	rb.AppendStr("\r\n\r\n")
	rb.AppendStr(last.requestBody.String())
	rec.RespW.Write(rb.Bytes())
	return
}

func (this *PlgNetHttpView) OnHttpCmd(w http.ResponseWriter, r *http.Request) {
	rec := NewPlgHttpRec(w, r)
	rec.CheckDecodeBody()

	rval, errcode, err := plgbase.ReloadPlgFromJSON(rec.Req)
	if err != nil {
		rec.ResponseJSONValues("code", -1, "errcode", errcode, "msg", err.Error())
	} else {
		if rval == nil {
			rec.ResponseJSONValues("code", 0)
		} else if json, ok := rval.(*wrapper.SuperValue); ok {
			PrjHttpUtils.ResponseJSON2(w, json)
		}
	}
}

func (this *PlgNetHttpView) OnHttpReload(w http.ResponseWriter, r *http.Request) {
	rec := NewPlgHttpRec(w, r)
	rec.CheckDecodeBody()

	err := plgbase.CheckReloadPlugFromJSONFile()
	if err != nil {
		rec.ResponseJSONValues("code", -1, "errcode", plgbase.ERR_INNER, "msg", err.Error())
	} else {
		rec.ResponseJSONValues("code", 0)
	}
}

func (this *PlgNetHttpView) OnHttPlugService(w http.ResponseWriter, r *http.Request) {
	rec := NewPlgHttpRec(w, r)

	rec.CheckDecodeBody()
	defer rec.Close()
	uri := r.URL.Path
	uri = strings.TrimPrefix(uri, "/plug/")
	if len(uri) == 0 {
		http.Error(w, fmt.Sprintf("invalid url(%s)!", uri), 503)
		return
	}
	plugid, path := utils.CutPrefixByRune(uri, 0, 0, '/')
	if len(plugid) == 0 {
		//http.Error(w, fmt.Sprintf("invalid url(%s)!", uri), 503)
		plugid = path
		path = ""
	}

	obj := plgbase.FindPluginByID(plugid)

	if obj == nil {
		http.Error(w, fmt.Sprintf("plug:%s not found!", plugid), 404)
	} else {
		rec.PlugPath = path
		if len(path) <= 1 { // "/", ""
			if !doPlugHttpIndex(obj, rec) {
				http.Error(w, fmt.Sprintf("plug:%s not support IHttpIndex", plugid), 503)
			}
			return
		}

		remainPath := strings.TrimPrefix(path, "/")

		/**
		  "do"
		  "do/xxx
		  "reload"
		*/
		action, remainPath1 := utils.CutPrefixByRune(remainPath, 0, 0, '/')
		if len(action) == 0 {
			action = remainPath1
			remainPath1 = ""
		}
		rec.UriAction = action
		actionlstr := strings.ToLower(action)
		if strings.Compare(actionlstr, "do") == 0 {
			if doPlugHttpDo(obj, rec) {
				return
			}
		} else if strings.Compare(actionlstr, "status") == 0 {
			if doPlugHttpStatus(obj, rec) {
				return
			}
		} else if strings.Compare(actionlstr, "reload") == 0 {
			if doPlugHttpReload(obj, rec) {
				return
			}
		}

		if !doPlugHttpIndex(obj, rec) {
			http.Error(w, fmt.Sprintf("plug:%s not support IHttpIndex", plugid), 503)
		}
		return
	}
}

func (this *PlgNetHttpView) OnHttPlugStatus(w http.ResponseWriter, r *http.Request) {
	rec := NewPlgHttpRec(w, r)
	rec.CheckDecodeBody()
	defer rec.Close()
	plugid := rec.QryAsString("id", "")
	if len(plugid) == 0 {
		json := wrapper.NewSVObject()
		json.SetKeyValues("runsecs", PrjHttpUtils.GetRunSecs(), "buildtime", plgbase.BUILD_TIME, "uuid", PrjConf.APP_UUID,
			"addr", r.RemoteAddr, "timeunixsecs", time.Now().Unix())
		w.Write(json.AsJSONBytes(false))
		return
	}
	obj := plgbase.FindPluginByID(plugid)
	if obj == nil {
		http.Error(w, fmt.Sprintf("plug:%s not found!", plugid), 503)
	} else {
		if intf, ok := obj.(IHttpStatus); ok {
			rval, errcode, err := intf.OnHttpStatus(rec)
			if err != nil {
				rec.ResponseJSONValues("code", -1, "errcode", errcode, "msg", err.Error())
			} else {
				if json, ok := rval.(*wrapper.SuperValue); ok {
					PrjHttpUtils.ResponseJSON2(w, json)
				}
			}
		} else {
			http.Error(w, fmt.Sprintf("plug:%s not support IHttpStatus", plugid), 503)
		}
	}
}

func (this *PlgNetHttpView) OnHttPlugChanged(w http.ResponseWriter, r *http.Request) {
	rec := NewPlgHttpRec(w, r)
	rec.CheckDecodeBody()
	defer rec.Close()
	plugid := rec.QryAsString("id", "")
	confrow := wrapper.NewSVObject()
	confrow.SetKeyValues("id", "id", "type", "type", "err", "err", "t", "time", "conf", "conf")
	json := wrapper.NewSVArray()

	plgbase.GetPlgChangedData(json, plugid)

	strTitle := confrow.AsJSONString(true)

	css := wrapper.NewSVArray()
	{
		c1 := css.AppendObject()
		c1.SetKeyValues("id", "id", "width", "150px")
	}
	{
		c1 := css.AppendObject()
		c1.SetKeyValues("id", "t", "width", "180px")
	}
	{
		c1 := css.AppendObject()
		c1.SetKeyValues("id", "err", "width", "180px")
	}
	{
		c1 := css.AppendObject()
		c1.SetKeyValues("id", "conf", "width", "500px")
	}
	PrjHttpUtils.JSON2TableEx(rec.RespW, strTitle, json.AsJSONString(false), css)
}

func (this *PlgNetHttpView) OnHttPlugDo(w http.ResponseWriter, r *http.Request) {
	rec := NewPlgHttpRec(w, r)
	rec.CheckDecodeBody()
	defer rec.Close()
	plugid := rec.QryAsString("id", "")
	obj := plgbase.FindPluginByID(plugid)
	if obj == nil {
		http.Error(w, fmt.Sprintf("plug:%s not found!", plugid), 503)
	} else {
		if intf, ok := obj.(IHttpDo); ok {
			rval, errcode, err := intf.OnHttpDo(rec)
			if err != nil {
				rec.ResponseJSONValues("code", -1, "errcode", errcode, "msg", err.Error())
			} else {
				if json, ok := rval.(*wrapper.SuperValue); ok {
					PrjHttpUtils.ResponseJSON2(w, json)
				}
			}
		} else {
			http.Error(w, fmt.Sprintf("plug:%s not support IHttpDo", plugid), 503)
		}
	}
}
